package com.ten.java.doinit;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.util.StatusPrinter;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.ten.java.doinit.common.Context;
import com.ten.java.doinit.service.DBService;
import com.ten.java.doinit.service.create.CreateFileService;
import com.ten.java.doinit.util.IOUtils;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.stream.Collectors;

/**
 * @author zhangxs
 * @date 2022/7/8 11:06
 */
@Slf4j
public class InitAPI {

    private InitAPI() {}

    /**
     * 工具预初始化
     */
    static {
        initPath();
        initLogback();
        initConfig();
    }

    /**
     * 创建文件
     * @param url 数据库连接路径
     * @param username 用户名
     * @param password 密码
     * @param projectPath 文件路径（创建文件会在该目录下进行创建）
     * @param packagePath 包路径
     * @return void
     * @author zhangxs
     * @date 2022/7/11 15:35
     */
    public static void create(String url, String username, String password, String projectPath, String packagePath) throws Exception {
        // 初始化连接配置
        Context.Config.init(url, username, password, projectPath, packagePath);

        // 获取库中的表信息
        Map<String, List<DBService.Column>> tableInfo = DBService.getTableInfo();

        // 遍历表信息生成文件
        List<Context.CreateOption> createOptions = Context.Config.createOptions;
        if (!CollectionUtils.isEmpty(createOptions)) {
            for (Context.CreateOption createOption : createOptions) {
                CreateFileService service = (CreateFileService) Class.forName(createOption.getClassName()).newInstance();
                service.create(tableInfo);
            }
        }
    }

    /**
     * 路径初始化
     * @param
     * @return void
     * @author zhangxs
     * @date 2022/7/12 15:55
     */
    public static void initPath() {
        // 获取操作系统名称
        String osName = System.getProperty("os.name");
        System.out.println(String.format("os name: %s", osName));

        // 获取该class的路径
        String path = new InitAPI().getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
        System.out.println(String.format("original path: %s", path));

        // 检查返回的路径是否带有.jar，带有则需要进行处理
        if (path.contains(".jar")) {
            path = path.substring(0, path.lastIndexOf(".jar!") + 4);
            if (osName.toLowerCase().contains("windows")) {
                path = new File(path.substring(6)).getParent();
            }
        }

        // 通过File对象自动对路径进行系统适配
        System.out.println(String.format("run path: %s", path));
        Context.runPath = path;
        Context.configPath = path + File.separator + "config";
    }

    /**
     * logback初始化
     * @param
     * @return void
     * @author zhangxs
     * @date 2022/7/12 15:56
     */
    public static void initLogback() {
        System.setProperty("APP_NAME", "doinit");
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(loggerContext);
        loggerContext.reset();
        try{
            System.setProperty("LOG_PATH", Context.runPath);
            File config = new File(Context.runPath + File.separator + "logback-spring.xml");
            System.out.println(String.format("config path: %s", config.getPath()));
            @Cleanup
            FileInputStream inputStream = new FileInputStream(config);
            configurator.doConfigure(inputStream);
            StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);
            log.info("配置logback完成");
        } catch (Exception e) {
            System.err.println("配置logback异常");
            e.printStackTrace();
        }
    }

    /**
     * 配置初始化
     * @param
     * @return void
     * @author zhangxs
     * @date 2022/7/12 15:55
     */
    public static void initConfig() {
        try {
            File configFile = new File(Context.configPath);
            String jsonStr = IOUtils.read(configFile);
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            Context.Config.author = jsonObject.getString("author");
            Context.Config.pattern = jsonObject.getString("pattern");
            Context.Config.charset = jsonObject.getString("charset");

            JSONArray jsonArray = jsonObject.getJSONArray("createOptions");
            List<String> Strings = jsonArray.toList(String.class, JSONReader.Feature.TrimString);
            Context.Config.createOptions = Strings.stream().map(createOption -> Context.CreateOption.valueOf(createOption)).collect(Collectors.toList());

            Context.Config.columnMap = jsonObject.getObject("columnMap", HashMap.class);
        } catch (Exception e) {
            log.error("读取配置文件异常：", e);
        }
    }

    public static void main(String[] args) {
        log.info("请按照提示依次输入参数：");

        Scanner scanner = new Scanner(System.in);
        System.out.print("url（连接数据库的路径，仅支持mysql5.8以上版本）：");
        String url = scanner.nextLine();

        scanner = new Scanner(System.in);
        System.out.print("username（用户名，需要有访问information_schema库的权限）：");
        String username = scanner.nextLine();

        scanner = new Scanner(System.in);
        System.out.print("password（密码）：");
        String password = scanner.nextLine();

        scanner = new Scanner(System.in);
        System.out.print("projectPath（项目路径，存放生成的文件的目录）：");
        String projectPath = scanner.nextLine();

        scanner = new Scanner(System.in);
        System.out.print("packagePath（生成文件的文件的包路径，例如com.ten.java.init）：");
        String packagePath = scanner.nextLine();
        
        log.info("url: {}, username: {}, password: {}, projectPath: {}, packagePath: {}", url, username, password, projectPath, packagePath);
        log.info("创建文件开始...");
        try {
            create(url, username, password, projectPath, packagePath);
            log.info("文件创建完成。");
        } catch (Exception e) {
            log.error("文件创建异常：", e);
        }
    }
}
